# -*- coding: utf-8 -*-

import json
import re
import unittest

import jsonpath as jsonpath
import requests as requests
from ddt import ddt

from app.base_app import BaseApp


@ddt
class AutoCase(BaseApp, unittest.TestCase):
    """
    任务测试-通过excel获取数据进行接口测试--全封装自动化

    data中相关信息都用json格式，如果该字段无内容，则为空json-->{}

    因为设定了上下文处理，无论是请求还是响应需要对数据做处理，都需要在json中书写"$变量$"，系统会通过正则表达式进行匹配和处理

    注意：
    1. 如果你的请求数据中包含$字符有可能无法获得预期结果
    2. 目前请求只支持get和post
    3. 断言只支持http和response的情况
    4. 断言支持Equal、NotEqual、True、False、IsNone、IsNotNone、In、NotIn
    """

    # 上下文管理
    context = {}

    def __init__(self, methodName="runTest"):
        unittest.TestCase.__init__(self, methodName)
        BaseApp.__init__(self)
        self.case_data = {}

    def _handle_excel_data(self, data):
        """
        处理excel数据
        :param data: excel读取的数据
        :return: 处理后的excel数据
        """

        # 正则查找$$内容
        pattern = re.compile(r'(\$(.*?)\$)')
        result = pattern.findall(data)
        for exp in result:
            # 替换json字符串中的$$内容
            data = data.replace(exp[0], self.context[exp[1]])

        data = json.loads(data)

        return data

    def _handle_request(self, request_url, request_method, request_header, request_param):
        """
        处理请求
        这里只实现的get和post
        :param request_url: 请求url
        :param request_method: 请求方法
        :param request_header: 请求header头
        :param request_param: 请求数据
        :return: response 响应结果
        """

        # print("【request_info】")
        request_info = {
            "case_id": self.case_data["case_id"],
            "case_name": self.case_data["case_name"],
            "request_url": request_url,
            "request_method": self.case_data["request_method"],
            "request_header": request_header,
            "request_param": request_param,
        }
        # print(request_info)

        # print("【response_info】")
        if request_method == "get":
            response = requests.get(request_url, headers=request_header, params=request_param)
            print(response.text)
        elif request_method=="post":
            response = requests.post(request_url, headers=request_header, json=request_param)
            print('===',response.text)
        else:
            response = requests.delete(request_url, data=request_param)
        return response

    def _handle_assert(self, response, assert_condition):
        """
        处理断言
        :param response: request请求结果
        :param assert_condition: excel中断言内容
        :return: void
        """

        for key in assert_condition:
            value = assert_condition[key]
            if value["type"] == "http":
                self.assertEqual(response.status_code, value["value"])
            else:
                xpath = "$..{name}".format(name=value["key"])
                condition_data = jsonpath.jsonpath(json.loads(response.text), xpath)[0]
                if value["assert"] == "Equal":
                    self.assertEqual(condition_data, value["value"])
                elif value["assert"] == "NotEqual":
                    self.assertNotEqual(condition_data, value["value"])
                elif value["assert"] == "True":
                    self.assertTrue(condition_data)
                elif value["assert"] == "False":
                    self.assertFalse(condition_data)
                elif value["assert"] == "IsNone":
                    self.assertIsNone(condition_data)
                elif value["assert"] == "IsNotNone":
                    self.assertIsNotNone(condition_data)
                elif value["assert"] == "In":
                    self.assertIn(condition_data, value["value"])
                elif value["assert"] == "NotIn":
                    self.assertNotIn(condition_data, value["value"])

    def _handle_context(self, response, context):
        """
        处理上下文
        :param response: request请求结果
        :param context: 上下文
        :return: void
        """

        # 正则查找$$内容
        pattern = re.compile(r'(\$(.*?)\$)')
        result = pattern.findall(context)
        for context_exp in result:
            # 替换json字符串中的$$内容
            xpath = "$..{name}".format(name=context_exp[1])
            replace_context = jsonpath.jsonpath(json.loads(response.text), xpath)[0]
            context = context.replace(context_exp[0], str(replace_context))
        context = json.loads(context)

        for key in context:
            self.context[key] = context[key]

    def run_case_test(self, case_data):
        """
        执行测试
        :param case_data: sheet中的一行case数据
        :return:
        """

        self.case_data = case_data

        case_id = str(case_data["case_id"])
        case_name = str(case_data["case_name"])
        request_url = str(case_data["request_url"])
        request_method = str(case_data["request_method"])
        request_header = str(case_data["request_header"])
        request_param = str(case_data["request_param"])
        assert_condition = json.loads(case_data["assert_condition"])
        context = str(case_data["context"])
        # print(request_header)
        print(case_name)
        self.log.debug("current case：" + case_id + "-->" + case_name)

        # 1.处理请求数据
        request_header = self._handle_excel_data(request_header)
        request_param = self._handle_excel_data(request_param)

        # 2.发起请求
        response = self._handle_request(request_url, request_method, request_header, request_param)
        # 3.断言
        # self._handle_assert(response, assert_condition)
        # if float(case_id) != 1:
        #     # status_code = jsonpath.jsonpath(json.loads(response.text), "$..msg")[0]
        #     status = response.status_code
        #     self.assertEqual(str(status), assert_condition['status'])
        # 4.上下文处理
        self._handle_context(response, context)
        return response